var chkbox_w = 25;
var lineHeight = 22;
let chkBoxHtml = "<td class='k_box_size'   style='border-left:none;text-align:center;' ><div style='width:" + chkbox_w + "px' class='k_box_size k_table_cell_chkbox'><i class='fa  fa-check-empty'></i></div></td>";
let tdHtml = "<td  class='k_box_size'><div class='k_box_size k_table_cell_text'><div style='width:100%' class='k_table_text k_box_size k_mutilline_ellipsis'></div></div></td>";

/**
 *列默认配置
 ***/
var defaultColOpts = {
    title: '',
    field: '', //字段
    width: 'auto',
    rowspan: 0, // 跨行
    colspan: 0, //跨列
    align: 'left', //对齐'left'、'right'、'center'
    sortable: false, //该列是否可以排序
    resizable: false, //可以调整宽度
    formatter: null //function (cellValue, rowData) {return cellValue }//单元格格式化函数
};
/**
 *table全局配置
 ***/
var defaultOpts = {
    title: '', //标题
    data: undefined, //列表数据 存在初始化数据时，优先用初始化数据
    url: undefined, //url
    fit2height: false, //是否只能占满父元素(垂直方向)
    loadImd: true, //是否立即加载    
    oprCol: true, //是否需要行操作列  
    treeIconColor: undefined,//树形图标颜色
    oprColWidth: 'auto', //操作列最小宽度，默认自动
    rows: [], //列配置，支持多表头
    idField: 'id', //id字段名称
    checkBox: true, //是否需要复选框
    isTree: false, //是否是树形列表
    pgposition: 'bottom', //分页工具栏位置 top,bottom,both ,none none表示不需要分页栏
    pageSize: 30, //页大小
    toolbar: undefined, //顶部工具栏，参考toolbar组件
    lineClamp: 3,//省略号行数
    showLoading:true,//是否显示正在加载
    openExtendTr: false, //是否默认打开展开行
    topBtnStyle: {
        methodsObject: 'tableMethods',
        style: 'normal', //plain   plain / min  / normal /  big             
        showText: true
    },
    trBtnStyle: {
        align: 'center', //对齐方式，默认是left 、center、right
        methodsObject: 'trMethods',
        style: 'plain', //plain   plain / min  / normal /  big             
        showText: true
    },
    pgBtnNum: 10, //页按钮数量
    pageList: [15, 20, 25, 30, 35, 40, 55, 70, 80, 90, 100], //页大小选择
    pgSummary: true,//是否需要总数量，页数提示
    pgButtonCss: undefined,
    iconCls: undefined, //图标   fa-table
    setParams: undefined, //设置参数
    splitColLine: 'k_table_td_all_line', //分割线样式 k_table_td_v_line、k_table_td_h_line，k_table_td_none_line
    sortField: undefined, //默认排序字段
    sortFieldPrex: '_col_sort_',//排序字段参数前缀
    onDbClickRow: null, // function (tr,data) { },//双击一行时触发 fn(tr,data)
    onClickCell: null, // function (field, value) { },//单击一个单元格时触发fn(field, value)
    onCheck: null, //function () { },//复选事件
    onCreateCheckbox:null, //fu(td,data) //当创建checkbox回调
    onRowRender: null, // function (tr,data,rownum) { },//行渲染事件，返回true则开启行展开功能 
    onLoaded: null, //function (data) { }//加载完成回调
    onToolCreated: null, //创建工具栏完成回调 
    onParentOpen:null ,//当展开父节点，用于拦截展开，返回false则不会执行内部请求
    onCreateRowToolbar:null,//行工具栏创建回调fn(opts,data)
    onTrExtended: null, //行展开事件 fn(data, extTr,isShow)
    formatTipFn: undefined //fn (colName,rowData,colIdx,rowIdx)
};
//树转合适顺序的列表
function _tree2list(res, beans) {
    if (!Array.isArray(beans)) {
        beans = [beans];
    }
    for (let i = 0; i < beans.length; i++) {
        let bean = beans[i];
        bean.depth = res.depth;
        res.arr.push(bean);
        if (bean.children) {
            _tree2list({ arr: res.arr, depth: res.depth + 1 }, bean.children);
        }
    }
}
function _createToolbar(ins, toolOps, warp, flagClazz) {
    if (Array.isArray(toolOps.buttons) && toolOps.buttons.length > 0) {      
        let toolbarEl = $B.DomUtils.prepend(warp, "<div class='k_table_toolbar_wrap k_box_size " + flagClazz + "'></div>");        
        let toolbarIns = new $B.Toolbar(toolbarEl, toolOps);
        if (typeof ins.onToolCreated === "function") {
            setTimeout(() => {
                ins.onToolCreated(toolbarIns);
            }, 1);
        }
        ins.toolbarIns = toolbarIns;
        return toolbarEl;
    }
}
/***
 * 创建顶部工具栏，考虑工具栏动态支持功能
 * ****/
function _createTopToolbarFn(ins) {
    ins.destroyTools()
    var toolOps = $B.extendObjectFn(true, {
        buttons: ins.opts.toolbar
    }, ins.opts.topBtnStyle);
    toolOps.align = 'left';
    if ($B.config && $B.config.tableTopToolOpts) {
        toolOps = $B.extendObjectFn(true, toolOps, $B.config.tableTopToolOpts);
    }
    let flagClazz = '_top_tool_';
    let toolWrap = _createToolbar(ins, toolOps, ins.elObj, flagClazz);
    let needtopPg = ins.opts.pgposition === "top" || ins.opts.pgposition === "both";
    if (!toolWrap && needtopPg) {
        toolWrap = $B.DomUtils.prepend(ins.elObj, "<div class='k_table_toolbar_wrap k_box_size " + flagClazz + "'></div>");
    }
    ins.$topToolWrap = toolWrap; //记录起来以便_createPagination使用
}
function _createHeaderTitle(ins) {
    if (ins.opts.title !== '') {
        ins.$title = $B.DomUtils.createEl("<div class='k_table_head_title k_box_size'><h6 style='overflow:hidden;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp:1' class=''><span class='k_table_h_txt'>" + ins.opts.title + "</span></h6></div>");
        ins.$H6 = ins.$title.firstChild;
        $B.DomUtils.prepend(ins.elObj, ins.$title);
        if (ins.opts.iconCls !== '') {
            $B.DomUtils.prepend(ins.$H6, '<i style="padding-right:6px;" class="fa ' + ins.opts.iconCls + '"></i>');
        }
    }
}
function getColIndexFn(element) {
    var colIndex = 0;
    var childs = element.childNodes;
    let child, colspan;
    for (let i = 0; i < childs.length; i++) {
        child = childs[i];
        colspan = $B.DomUtils.attribute(child, "colspan");
        if (colspan) {
            colIndex = colIndex + parseInt(colspan);
        } else {
            colIndex = colIndex + 1;
        }
    }
    return colIndex;
}
function fixCheckAndOpr(arr) {
    if (arr.length > 1) {
        for (let j = 0; j < arr.length; j++) {
            if (j === 0) {
                $B.DomUtils.attribute(arr[j], { rowspan: arr.length });
            } else {
                arr[j].parentNode.removeChild(arr[j]);
            }
        }
    }
}
function _cretteTableHeader(ins) {
    $B.DomUtils.removeChilds(ins.$headWrap);//先清理已经渲染的头部
    ins.$headTable = $B.DomUtils.createEl("<table></table>");
    var opts = ins.opts;
    var rowspanColMap = {},
        rows = opts.rows,
        delTdArr = [],
        lastRowIndex = rows.length - 1,
        isCheckBox = opts.checkBox,
        row,
        td,
        tr,
        colIndex,
        opt,
        tdOptMap = {},
        oprTitle = $B.config && $B.config.oprColName ? $B.config.oprColName : "action",
        isLastRow, tdAttr, tdCss, $tdTxtDiv,
        sortEl = $B.DomUtils.createEl("<div style='position:absolute;'  class='k_table_cell_sort k_box_size'><i style='bottom:14px' class='fa fa-up-dir'></i><i  style='bottom:2px' class='fa fa-down-dir'></i></div>"),
        modelTr = $B.DomUtils.createEl("<tr></tr>"),
        modelTd = $B.DomUtils.createEl("<td  class='k_box_size'><div class='k_box_size k_table_cell_text'><div style='width:100%' class='k_table_title_text k_box_size'></div></div></td>");
    /****
     * 先创建好tr td html放置于数组中，最后循环一次appendto
     * 处理colspan情况，colspan不需要处理，外部的json已经要求不能有多余的td
     * 处理rowspan情况
     * *****/
    let checkBoxArr = [];
    let oprArr = [];
    let maxColCount = 0;
    let lastColIndex = 0;
    for (let rowIdx = 0, l = rows.length; rowIdx < l; ++rowIdx) {
        row = rows[rowIdx];
        tr = modelTr.cloneNode();
        $B.DomUtils.append(ins.$headTable, tr);      
        isLastRow = rowIdx === lastRowIndex;
        if (isLastRow) {
            lastColIndex = row.length - 1; //计算记录共有多少列;
        }
        if (isCheckBox) { //复选框功能
            let chkTd = $B.DomUtils.createEl("<td class='k_box_size'  row='" + rowIdx + "' col='0'  ischk='1' style='border-left:none;' ><div style='width:" + chkbox_w + "px' class='k_box_size k_table_cell_chkbox'><i class='fa  fa-check-empty'></i></div></td>");
            $B.DomUtils.append(tr, chkTd);
            if (rowIdx === 0) {
                tdOptMap[rowIdx + "_0"] = { isCheckBox: true, width: chkbox_w };
                $B.DomUtils.css(chkTd, { "border-top": "none" });
                ins.$chkTdBtn = chkTd.firstChild;
                ins._bindHeadChkEvent(chkTd);
            }
            checkBoxArr.push(chkTd);
            chkTd._col = 0;
            chkTd._isHeader = true;
            chkTd._ischk = true;
        }
        for (let j = 0, jl = row.length; j < jl; ++j) {
            opt = isLastRow ? $B.extendObjectFn(true, {}, defaultColOpts, row[j]) : row[j];//最后一行才执行列默认配置合并
            if (!opt.width || opt.width === "") {
                opt.width = "auto";
            } else if (opt.width !== "auto") {
                opt.width = (opt.width + "").replace("px", "");
            }
            td = modelTd.cloneNode(true);
            colIndex = getColIndexFn(tr);
            tdAttr = { row: rowIdx, col: colIndex ,field:opt.field};
            if(opt.openTip){
                tdAttr["tip"] = "";
            }
            td._col = colIndex;
            if (opt.colspan) {
                let cl = parseInt(opt.colspan);
                if (cl > 1) {
                    tdAttr["colspan"] = cl;
                }
            }
            if (opt.rowspan) {
                let cl = parseInt(opt.rowspan);
                if (cl > 1) {
                    tdAttr["rowspan"] = cl;
                }
            }
            tdCss = {};
            if (rowIdx === 0) {
                tdCss["border-top"] = "none";
            }
            if (j === 0 && !isCheckBox) {
                tdCss["border-left"] = "none";
            }
            if ((j === jl - 1) && !ins.opts.oprCol) {
                tdCss["border-right"] = "none";
            }
            $tdTxtDiv = td.firstChild.firstChild;
            $B.DomUtils.html($tdTxtDiv, opt.title);
            if (opt.sortable) {
                $B.DomUtils.append(td, sortEl.cloneNode(true));
                ins.bindSortEvents(td);
            }
            //$B.DomUtils.outerWidth(td, opt.width);
            $B.DomUtils.css(td, tdCss);
            /***
             *循环已经添加到tr的td，计算当前的列索引 需要处理colspan的情况
             ****/
            //记录td归属的行、列            
            tdOptMap[rowIdx + "_" + colIndex] = opt;
            $B.DomUtils.append(tr, td);
            //处理被前面行rowspan的元素
            let rowKeys = Object.keys(rowspanColMap);
            for (let r = 0; r < rowKeys.length; r++) {
                let rNum = parseInt(rowKeys[r]);
                if (rNum < rowIdx) {
                    let rowSpanTdArr = rowspanColMap[rowKeys[r]];
                    let currentTdEndIdx = colIndex;
                    if (tdAttr.colspan) {
                        currentTdEndIdx = currentTdEndIdx + tdAttr.colspan - 1;
                    }
                    for (let k = 0; k < rowSpanTdArr.length; k++) {
                        let spTd = rowSpanTdArr[k];
                        let rowSpn = parseInt($B.DomUtils.attribute(spTd, "rowspan")) + rNum;
                        if (rowSpn > rowIdx) {
                            let startIdx = parseInt($B.DomUtils.attribute(spTd, "col"));
                            let endIdx = startIdx;
                            let colSpn = $B.DomUtils.attribute(spTd, "colspan");
                            if (colSpn) {
                                endIdx = startIdx + parseInt(colSpn) - 1;
                            }
                            //当前列号范围在合并单元格的列号范围内，说明这是一个被合并的单元格
                            //判定被合并的单元格是否存在colspan，存在则做colspan减除，否则是需要删除的
                            let isFix;
                            if (colIndex < startIdx) {
                                isFix = currentTdEndIdx >= startIdx;
                            } else {
                                isFix = startIdx <= colIndex && colIndex <= endIdx;
                            }
                            if (isFix) {
                                if (tdAttr.colspan) { //当前td是否存在colspan
                                    let diff = 1;
                                    if (colSpn) {
                                        diff = parseInt(colSpn);
                                    }
                                    tdAttr.colspan = tdAttr.colspan - diff;
                                    if (tdAttr.colspan < 1) {
                                        delTdArr.push(td);
                                    } else if (tdAttr.colspan === 1) {
                                        delete tdAttr.colspan;
                                    }
                                } else {
                                    delTdArr.push(td);
                                }
                            } else {
                                break;
                            }
                        }
                    }
                }
            }
            $B.DomUtils.attribute(td, tdAttr);
            /*判断是否是被rowspan的单元格
             *1)先将rowspan的列记录到rowspanCol,记录当前rowspan的范围
             *2)如果该列存在rowspan，则取出然后判断当前的td是否在rowspan范围内，如果在则记录起来
             * *****/
            if (tdAttr["rowspan"]) {
                if (!rowspanColMap[rowIdx]) {
                    rowspanColMap[rowIdx] = [];
                }
                rowspanColMap[rowIdx].push(td);
            }
            td._isHeader = true;
        }
        if (ins.opts.oprCol) {//操作列  
            colIndex++;
            let opTd = modelTd.cloneNode(true);
            opTd._isHeader = true;
            let opCss = { "border-right": "none" };
            // if (ins.opts.oprColWidth) {
            //     opCss.width = ins.opts.oprColWidth;
            // }
            $B.DomUtils.css(opTd, opCss);
            $B.DomUtils.attribute(opTd, { row: rowIdx, col: colIndex });
            $B.DomUtils.html(opTd.firstChild.firstChild, oprTitle);
            $B.DomUtils.append(tr, opTd);
            if (rowIdx === 0) {
                let _key = rowIdx + "_" + colIndex;
                tdOptMap[_key] = { isOpr: true, width: 'auto' };
                if (ins.opts.oprColWidth) {
                    tdOptMap[_key].width = ins.opts.oprColWidth;
                }
                $B.DomUtils.css(opTd, { "border-top": "none" });
            }
            oprArr.push(opTd);
            opTd._col = colIndex;
        }
        if (colIndex > maxColCount) {
            maxColCount = colIndex;
        }
    }
    //修正checkbox opr操作列
    fixCheckAndOpr(checkBoxArr);
    fixCheckAndOpr(oprArr);
    //删除被rowspan的td
    var waitingMegerOpt = {};
    for (let d = 0, ll = delTdArr.length; d < ll; ++d) {
        let rNumb = parseInt($B.DomUtils.attribute(delTdArr[d], "row"));
        let cNumb = $B.DomUtils.attribute(delTdArr[d], "col");
        let optKey = rNumb + "_" + cNumb;
        if (rNumb === lastRowIndex) {
            waitingMegerOpt[cNumb] = tdOptMap[optKey];
        }
        delete tdOptMap[optKey];
        delTdArr[d].parentNode.removeChild(delTdArr[d]);
    }
    //添加一个隐藏行
    ins.$hideTr = $B.DomUtils.createEl("<tr style='height:0px;'></tr>");
    let i = 0, $td, css, attr;
    let tdHtml = "<td><div></div></td>";
    ins.colOptArray = [];
    ins.autoCols = [];
    while (i <= maxColCount) {
        $td = $B.DomUtils.createEl(tdHtml);
        css = { "border-top": "none", "border-bottom": "none" };
        attr = { col: i };
        if (i === 0) {
            css["border-left"] = "none";
        } else if (i === maxColCount) {
            css["border-right"] = "none";
        }
        $B.DomUtils.css($td, css);
        $B.DomUtils.attribute($td, attr);
        $B.DomUtils.append(ins.$hideTr, $td);
        let r = rows.length;
        let key = r + "_" + i;
        let opt = tdOptMap[key];
        while (!opt) {
            if (r === 0) {
                break;
            }
            r = r - 1;
            key = r + "_" + i;
            opt = tdOptMap[key];
        }
        if (waitingMegerOpt[i]) {
            opt = $B.extendObjectFn(opt, waitingMegerOpt[i]);
        }
        ins.colOptArray.push(opt);
        //获取字符宽度，灵活设置列的最大，最小宽度
        let chartWidth = $B.getCharWidth(opt.title);
        opt.minWidth = chartWidth + 16;
        if (opt.sortable) {
            opt.minWidth = chartWidth + 20;
        }
        if ((opt.width + "") === "auto") {
            ins.autoCols.push(i);
        } else {
            $B.DomUtils.css($td.firstChild, { width: opt.width });
        }
        i++;
    }
    ins.colTdMap = {};
    //提取所有标题单元格
    for (let i = 0; i < ins.$headTable.children.length; i++) {
        let r = ins.$headTable.children[i];
        for (let j = 0; j < r.children.length; j++) {
            let _td = r.children[j];
            _td._isHeader = true;
            let colIdx = _td._col;
            ins.colTdMap[colIdx] = _td;
        }
    }
    $B.DomUtils.prepend(ins.$headTable, ins.$hideTr);
    $B.DomUtils.prepend(ins.$headWrap, ins.$headTable);
    ins.autoHeaderWidth();   
    let colKeys = Object.keys( ins.colTdMap);
    for (let t = 0; t < colKeys.length; t++) {
        ins._bindTdEvents(ins.colTdMap[colKeys[t]]);
    }
}
function _appendEmptyTr(ins, msg) {
    let w = $B.DomUtils.width(ins.$bodyTable.parentNode) - 2;
    let emptyTr = $B.DomUtils.createEl("<tr><td style='text-align:center;'><div style='width:" + w + "px'><i style='color:#F5C400;padding-right:8px;' class='fa fa-attention'></i>" + msg + "</div></td></tr>");
    if (msg === "") {
        emptyTr.firstChild.firstChild.innerHTML = "";
    }
    ins.$bodyTable.appendChild(emptyTr);
    return emptyTr;
}
function _createTr(ins, rowNum, data) {
    var isTree = ins.opts.isTree;
    let tr = document.createElement("tr");
    let idVal;
    if (isTree) {
        $B.DomUtils.attribute(tr, { "deep": data.depth });
        idVal = data.data ? data.data[ins.opts.idField] : data[ins.opts.idField];
    }else{
        idVal = data[ins.opts.idField];
    }
    
    $B.DomUtils.attribute(tr,{"data-id":idVal});
    let isHline = ins.opts.splitColLine.indexOf('td_h_line') > 0 ||  ins.opts.splitColLine.indexOf('td_none_line') > 0;
    let firstCol = true;
    for (let j = 0; j < ins.colOptArray.length; j++) {
        let opt = ins.colOptArray[j];
        let td, tdAttr = { row: rowNum, col: j };
        if (opt.isCheckBox) {//复选框列
            td = $B.DomUtils.append(tr, chkBoxHtml);
            tdAttr["ischk"] = 1;
            if (data._checked) { //复选
                let $i = td.firstChild.firstChild;
                $B.DomUtils.removeClass($i, "fa-check-empty fa-minus-squared");
                $B.DomUtils.addClass($i, "fa-check");
            }
            td._ischk = true;
            if(isHline){
                td.style.width = (chkbox_w + 1) + "px";
            }
            if(ins.opts.onCreateCheckbox){
                ins.opts.onCreateCheckbox(td,data);
            }
        } else {
            td = $B.DomUtils.append(tr, tdHtml);
            if (opt.isOpr) {//操作列 rowTools
                tdAttr["isopr"] = 1;
                let btnOpts = $B.extendObjectFn(true, {params:data}, ins.opts.trBtnStyle);
                btnOpts["buttons"] = data.toolbar;  
                if(ins.opts.onCreateRowToolbar){
                    ins.opts.onCreateRowToolbar(btnOpts,data);
                }             
                let toolIns = new $B.Toolbar(td.firstChild.firstChild, btnOpts);
                ins.rowTools.push(toolIns);
                delete data.toolbar;
            } else {//普通数据列
                let field = opt.field;                
                let val,dataObj = data;
                if (isTree && data.data) {
                    dataObj = data.data;
                } 
                if(field.indexOf(".") > 0){
                    let paths = field.split(".");
                    let jlen = paths.length - 1;
                    for(let j =0 ; j < jlen;j++){
                        dataObj = dataObj[paths[j]];
                    }
                    val = dataObj[paths[jlen]]; 
                }else{
                    val = dataObj[field]; 
                }                           
                if (opt.formatter) {
                    let tmpVal;
                    if ((typeof opt.formatter === "string") && typeof window[opt.formatter] === "function") {
                        tmpVal = window[opt.formatter].call(td,val, data);
                    } else if (typeof opt.formatter === "function") {
                        tmpVal = opt.formatter.call(td, val, data);
                    }
                    if(typeof tmpVal !== undefined && typeof tmpVal !== "boolean"){
                        val = tmpVal;
                    }else if(typeof tmpVal === "boolean" && !tmpVal){
                        val = undefined;
                    } else{
                        val = tmpVal;
                    }                  
                }
                let isTreeTitleCol = isTree && firstCol;
                if (isTreeTitleCol) {
                    firstCol = false;
                    opt.align = "left";
                    //根据deepth
                    let depth = data.depth;
                    let htmlArr = [];
                    while (depth > 0) {
                        htmlArr.push("<span class='_tree_span' style='display:inline-block;width:18px;'></span>");
                        depth--;
                    }
                    if (data.children) {
                        let iconFold = "fa-folder-open";
                        if (data.children.length === 0) {
                            iconFold = "fa-folder";
                        }
                        htmlArr.push("<span class='tree_fold_ _tree_span' style='display:inline-block;width:16px;padding-right:5px;'><i style='cursor:pointer;' class='fa " + iconFold + "'></i></span>");
                        ins._bindTreeEvents(td);
                    } else {
                        htmlArr.push("<span class='_tree_span' style='display:inline-block;width:16px;padding-right:5px'><i class='fa fa-doc'></i></span>");
                    }
                    val = htmlArr.join("") + (val === undefined ? "" : val);                   
                    $B.DomUtils.css(td.firstChild.firstChild,{"-webkit-line-clamp":1});
                }
                if(val !== undefined){
                    td.firstChild.firstChild.innerHTML = val;
                }                
                if (opt.align) {
                    $B.DomUtils.css(td, { "text-align": opt.align });
                }
                //最大省略号行数
                let maxHeight = ins.opts.lineClamp * lineHeight;
                $B.DomUtils.css(td.firstChild, { "max-height": maxHeight });
                if(!isTreeTitleCol){
                    $B.DomUtils.css(td.firstChild.firstChild, { "-webkit-line-clamp": ins.opts.lineClamp,"word-break":"break-all" });
                }                
                ins._bindTdEvents(td);
            }
        }
        //if (rowNum === 0) {
            let tdWidth = ins.colWidthArray[j];
            if (isHline) {
                tdWidth++;
            }
            $B.DomUtils.outerWidth(td.firstChild, tdWidth);
        //}
        $B.DomUtils.addClass(td, ins.opts.splitColLine);
        $B.DomUtils.attribute(td, tdAttr);
        td._col = j;
        td._row = rowNum;
    }
    let ret = false;
    if(ins.opts.onRowRender){
        ret = ins.opts.onRowRender(tr, data, rowNum);
    }
    if (typeof ret !== "undefined" && ret) {
        ins.extendTr(tr);
    }
    return tr;
}
function _makeTrByFragment(ins, datas) {
    ins.formatDataArr = [];
    ins.destroyRowTools();
    if (ins.opts.data.totalSize === 0) {
        ins._makeEmptyTrTip();
        return;
    }
    ins.$emptyTr = undefined;
    var fragment = document.createDocumentFragment();
    for (let i = 0; i < datas.length; i++) {
        let data = datas[i];
        let tr = _createTr(ins, i, data);
        fragment.appendChild(tr);
        ins.formatDataArr.push(data);
    }
    $B.DomUtils.removeChilds(ins.$bodyTable);
    ins.opts.data = undefined;
    return fragment;
}
function _cretteTableBody(ins) {
    //更新分页工具栏
    if (ins.topPgIns) {
        ins.topPgIns.update(ins.page, ins.opts.pageSize, ins.opts.data.totalSize);
    }
    if (ins.bottomPgIns) {
        ins.bottomPgIns.update(ins.page, ins.opts.pageSize, ins.opts.data.totalSize);
    }
    let fragment = _makeTrByFragment(ins, ins.opts.data.resultList);
    if(fragment){
        ins.$bodyTable.appendChild(fragment);
    }   
}
function _createPagination(ins) {
    if (ins.opts.isTree) {
        return;
    }
    if ($B["Pagination"]) {
        var $topWrap = ins.$topToolWrap;
        var total = ins.opts.data && ins.opts.data.totalSize ? ins.opts.data.totalSize : 0;
        let pgOpt = {
            total: total,
            page: ins.page,
            pageList: ins.opts.pageList, //页大小项
            buttons: ins.opts.pgBtnNum,
            pageSize: ins.opts.pageSize,
            summary: ins.opts.pgSummary,
            buttonCss: ins.opts.pgButtonCss,
            onClick: function (page, pageSize) {               
                ins.page = page;
                ins.opts.pageSize = pageSize;
                ins._load();
            }
        };
        if (ins.topPgIns) {
            ins.topPgIns.destroy();
            ins.topPgIns = undefined;
        }
        ins.destroyBottomTools();
        if (ins.opts.pgposition === "top" || ins.opts.pgposition === "both") {
            if (ins.toolbarIns) {
                let $pgWrap = $B.DomUtils.createEl("<div style='float:right'></div>");
                $topWrap.appendChild($pgWrap);
                $topWrap = $pgWrap;
            }
            ins.topPgIns = new $B.Pagination($topWrap, pgOpt);
        }
        if (ins.opts.pgposition === "bottom" || ins.opts.pgposition === "both") {
            let $pgWrap = $B.DomUtils.createEl("<div class='k_box_size' style=''></div>");
            ins.elObj.appendChild($pgWrap);
            ins.bottomPgIns = new $B.Pagination($pgWrap, pgOpt);
        }
    }
}
function _cretteTreeTableBody(ins) {
    let list = { arr: [], depth: 0 };
    let data = ins.opts.data;
    if(data.resultList){
        data = data.resultList;
    }
    _tree2list(list, data);
    ins.opts.data = list.arr;
    let fragment = _makeTrByFragment(ins, ins.opts.data);
    ins.$bodyTable.appendChild(fragment);
}
function _getTd(pNode) {
    while (pNode) {
        if (pNode.tagName === "TD") {
            break;
        }
        pNode = pNode.parentNode;
    }
    return pNode;
}
class Table extends $B.BaseControl {
    constructor(elObj, opts) {
        super();
        super.setElObj(elObj);
        this.page = 1;
        this.toolbarIns = undefined;
        this.formatDataArr = [];       
        this.rowTools = [];
        this.exttrMap = {};//扩展行map
        var tableEl = this.elObj;
        $B.DomUtils.addClass(this.elObj, "k_table_tbody");
        var tableHtml = this.elObj.outerHTML;
        this.opts = $B.extendObjectFn(true, {}, defaultOpts, opts);
        if (!$B.isArrayFn(this.opts.rows[0])) { //多维表头
            this.opts.rows = [this.opts.rows];
        }
        this.elObj = $B.DomUtils.createEl('<div style="overflow:hidden" class="k_table_main_wrap k_box_size">'
            + '<div style="overflow-x:hide;position:relative;" class="k_table_hscroll_wrap k_box_size">'
            + '<div style="overflow-x:visible;" class="k_table_head_wrap k_box_size"></div>'
            + '<div class="k_table_body_wrap k_box_size" style="width:auto;"></div>'
            + '</div></div>');
        this.$hsrollEl = $B.DomUtils.children(this.elObj, ".k_table_hscroll_wrap")[0];
        this.$headWrap = $B.DomUtils.children(this.$hsrollEl, ".k_table_head_wrap")[0];
        this.$bodyWrap = $B.DomUtils.children(this.$hsrollEl, ".k_table_body_wrap")[0];

        //这里需要考虑元素被声明了位置的情况
        let posAttr = $B.DomUtils.css(tableEl, "position");
        if (posAttr !== "static") {
            let cssinf = $B.DomUtils.domInfo(tableEl);
            $B.DomUtils.css(this.elObj, { position: posAttr, top: cssinf.top, left: cssinf.left });
            tableEl.style.position = "static";
        }
        var _this = this;
        $B.DomUtils.scroll(this.$hsrollEl, function (e) {
            _this._updateSrollIcon();
            _this._closeToolTip();
        });
        this.$bodyWrap = $B.myScrollbar(this.$bodyWrap, {
            unScroll: 'hidden',
            scrollAxis: 'y',
            isHide: true,
            onScrollFn: function () {
                _this._closeToolTip();
            },
            onMkScrollFn: (wrap) => {
                if (!this.$scrolyIcon) {
                    let els = $B.DomUtils.children(wrap, ".k_scrollbar_y");
                    if (els.length > 0) {
                        this.$scrolyIcon = els[0];
                    }
                }
                this._updateSrollIcon();
            }
        });
        $B.DomUtils.append(this.$bodyWrap, tableHtml);
        $B.DomUtils.after(tableEl, this.elObj);
        $B.DomUtils.remove(tableEl);
        this.$bodyTable = $B.DomUtils.children(this.$bodyWrap, "table")[0];
        this.colOptArray = [];
        _createTopToolbarFn(this);
        _createHeaderTitle(this);
        _cretteTableHeader(this);
        if (!this.opts.isTree) {
            this.createPagination();
        }
        this.fit2height();
        if (this.opts.splitColLine === 'k_table_td_v_line') {
            $B.DomUtils.addClass(this.$bodyTable, "k_table_tbody_even");
        }
        if (this.opts.data) {
            if (this.opts.isTree) { //树形
                _cretteTreeTableBody(this);
            } else {
                _cretteTableBody(this);
            }
            this._triggerExentdTrs();
        } else if (this.opts.url && this.opts.loadImd) {
            this._load();
        } else {
            this._makeEmptyTrTip();
        }
        var _this = this;
        var isReqFrame = false;
        var resizeEvent = function () {
            if (!isReqFrame) {
                isReqFrame = true;
                requestAnimationFrame(() => {
                    isReqFrame = false;
                    if (_this.asyncWidth) {
                        _this.autoHeaderWidth();
                        _this.asyncWidth();
                    } else {
                        $B.DomUtils.offEvents(window, resizeEvent);
                    }
                });
            }
        };
        this.resizeEvent = resizeEvent;
        $B.DomUtils.resize(window, this.resizeEvent, 100);
        this.bindTableEvents();
    }
    _triggerExentdTrs() {
        if (this.triggerExtendTrs) {
            let triggers = this.triggerExtendTrs;
            this.triggerExtendTrs = [];
            setTimeout(() => {
                for (let i = 0; i < triggers.length; i++) {
                    $B.DomUtils.trigger(triggers[i], "click");
                }
            }, 0);
        }
    }
    _executeTreeTrUi(tr, deep, isOpen) {
        let nextTr = tr.nextSibling;
        while (nextTr) {
            if ($B.DomUtils.hasClass(nextTr, "_ext_tr")) {
                if (isOpen) {
                    nextTr.style.display = "table-row";
                } else {
                    nextTr.style.display = "none";
                }
                nextTr = nextTr.nextSibling;
            }
            let nextDeep = parseInt($B.DomUtils.attribute(nextTr, "deep"));
            if (nextDeep <= deep) {
                break;
            }
            if (isOpen) {
                //当展开的时候，并不一定是所有都展开，其子元素肯定是展开的，但是子元素的下的子元素不一定是展开的
                //检查本行是不是父元素，如果是父元素需要检查是否存在子元素，如果存在，需要检查这个节点是否是收起状态
                let row = parseInt($B.DomUtils.attribute(nextTr.firstChild, "row"));
                let data = this.formatDataArr[row];
                if (data.children) {//如果是父元素
                    $B.slideDown(nextTr, 100);//直接展开即可
                    let $foldEl;
                    if (this.opts.checkBox) {
                        $foldEl = $B.DomUtils.findByClass(nextTr.firstChild.nextSibling, "tree_fold_")[0].firstChild;
                    } else {
                        $foldEl = $B.DomUtils.findByClass(nextTr.firstChild, "tree_fold_")[0].firstChild;
                    }
                    if (data.children.length > 0) {//已经存在了子元素
                        if ($B.DomUtils.hasClass($foldEl, "fa-folder")) {//是隐藏的节点                            
                            nextTr = this._executeTreeTrUi(nextTr, nextDeep, false);
                            continue;
                        }
                    } else {
                        $B.DomUtils.addClass($foldEl, "fa-folder");
                        $B.DomUtils.removeClass($foldEl, "fa-folder-open");
                    }
                } else {
                    $B.slideDown(nextTr, 100);
                }
            } else {
                $B.slideUp(nextTr, 100);//当收起时候，所有都会收起
            }
            nextTr = nextTr.nextSibling;
        }
        return nextTr;
    }
    _bindTreeEvents(td) {
        if (!this.treeClickEvent) {
            var _this = this;
            this.treeClickEvent = function (e) {
                let el = e.target;
                if (el.tagName === "SPAN") {
                    el = el.parentNode;
                }
                if (el.tagName !== "I") {
                    return false;
                }
                let tr = e.target;
                while (tr) {
                    if (tr.nodeName === "TR") {
                        break;
                    }
                    tr = tr.parentNode;
                }
                let isOpen = true;
                if ($B.DomUtils.hasClass(el, "fa-folder-open")) {
                    $B.DomUtils.removeClass(el, "fa-folder-open");
                    $B.DomUtils.addClass(el, "fa-folder");
                    isOpen = false;
                } else {
                    $B.DomUtils.addClass(el, "fa-folder-open");
                    $B.DomUtils.removeClass(el, "fa-folder");
                }
                let deep = parseInt($B.DomUtils.attribute(tr, "deep"));
                if (isOpen) {
                    let row = parseInt($B.DomUtils.attribute(tr.firstChild, "row"));
                    let data = _this.formatDataArr[row];
                    if (data.children.length === 0) {
                        let goRq = true;
                        if(_this.opts.onParentOpen){
                            let r = _this.opts.onParentOpen.call(el,data);
                            if(typeof r !== "undefined"){
                                goRq = r;
                            }
                        }
                        if(goRq){
                            $B.DomUtils.removeClass(el, "fa-folder fa-folder-open");
                            $B.DomUtils.addClass(el, "fa-spin5 animate-spin");                       
                            let prs = {pid:data.id};
                            _this._load(prs, function (isOk, childs) {
                                if (isOk) {
                                    if (!Array.isArray(childs)) {
                                        childs = [childs];
                                    }
                                    if (childs.length === 0) {
                                        $B.toolTip(el, ($B.config && $B.config.returnEmptyData) ? $B.config.returnEmptyData : 'the return is empty!', 1.6);
                                        return;
                                    }
                                    data.children = childs;
                                    _this._appendTree(tr, childs);
                                } else {
                                    $B.DomUtils.removeClass(el, "fa-spin5 animate-spin");
                                    $B.DomUtils.addClass(el, "fa-folder-open");
                                }
                            });
                        }                        
                        return false;
                    }
                }
                _this._executeTreeTrUi(tr, deep, isOpen);
                return false;
            };
        }
        setTimeout(() => {
            let $fold = $B.DomUtils.findByClass(td, "tree_fold_")[0];
            $B.DomUtils.click($fold, this.treeClickEvent);
        }, 0);
    }
    _appendTree(tr, childs) {
        let currentTr = tr;
        let deep = parseInt($B.DomUtils.attribute(tr, "deep"));
        let row = parseInt($B.DomUtils.attribute(tr.firstChild, "row")) + 1;
        let newFormateData = this.formatDataArr.slice(0, row);
        let leftFormatData;
        if (row < this.formatDataArr.length) {
            leftFormatData = this.formatDataArr.slice(row);
        }
        let list = { arr: [], depth: deep + 1 };
        _tree2list(list, childs);
        list = list.arr;
        for (let i = 0; i < list.length; i++) {
            let bean = list[i];
            let newtr = _createTr(this, row, bean);
            $B.DomUtils.after(currentTr, newtr);
            newFormateData.push(bean);
            currentTr = newtr;
            row++;
        }
        //更新后面的行号
        let nextTr = currentTr.nextSibling;
        while (nextTr) {
            let tdArr = $B.DomUtils.children(nextTr);
            for (let j = 0; j < tdArr.length; j++) {
                tdArr[j]._row = row;
                $B.DomUtils.attribute(tdArr[j], { row: row });
            }
            row++;
            nextTr = nextTr.nextSibling;
        }
        if (leftFormatData) {
            this.formatDataArr = newFormateData.concat(leftFormatData);
        } else {
            this.formatDataArr = newFormateData;
        }
    }
    _makeEmptyTrTip() {
        $B.DomUtils.removeChilds(this.$bodyTable);
        this.opts.data = undefined;
        let msg = $B.config && $B.config.returnEmptyData ? $B.config.returnEmptyData : "the return is empty!";
        this.$emptyTr = _appendEmptyTr(this, msg);
    }
    bindSortEvents(td) {
        var _this = this;
        if (!this.sortEvents) {
            this.sortEvents = {
                click: function (e) {
                    if (e.target.nodeName === "I") {
                        let td = e.target.parentNode.parentNode;
                        let col = parseInt($B.DomUtils.attribute(td, "col"));
                        let filed = _this.opts.sortFieldPrex + _this.colOptArray[col].field;
                        let params = {};
                        if ($B.DomUtils.hasClass(e.target, "fa-up-dir")) {
                            params[filed] = "asc";
                        } else {
                            params[filed] = "desc";
                        }
                        _this._load(params);
                    }
                }
            };
        }
        $B.DomUtils.bind(td, this.sortEvents);
    }
    _bindHeadChkEvent(td) {
        if (!this.chkEvents) {
            var _this = this;
            this.chkEvents = {
                click: function (e) {                    
                    var $i = e.target;
                    if ($i.tagName !== "I") {
                        $i = e.target.firstChild;
                    }
                    if ($B.DomUtils.hasClass($i, "fa-check")) {
                        $B.DomUtils.removeClass($i, "fa-check  fa-minus-squared");
                        $B.DomUtils.addClass($i, "fa-check-empty");
                        _this.checkAllData(false);
                    } else {
                        $B.DomUtils.removeClass($i, "fa-check-empty  fa-minus-squared");
                        $B.DomUtils.addClass($i, "fa-check");
                        _this.checkAllData(true);
                    }
                    return false;
                }
            };
        }
        $B.DomUtils.bind(td.firstChild, this.chkEvents);
    }
    bindTableEvents() {
        var _this = this;
        $B.DomUtils.bind(this.$bodyTable, {
            click: function (e) {
                if (_this.splitedLeftTd || _this.dragging) {
                    return false;
                }
                clearTimeout(_this.clickTimer);
                _this.clickTimer = setTimeout(() => {
                    let pNode = _getTd(e.target);
                    if ($B.DomUtils.attribute(pNode, "ischk")) {
                        _this._fireCheck(pNode);
                    } else if (!$B.DomUtils.attribute(pNode, "isopr")) {
                        let row = parseInt($B.DomUtils.attribute(pNode, "row"));
                        let col = parseInt($B.DomUtils.attribute(pNode, "col"));
                        let data = _this.formatDataArr[row];
                        if (_this.opts.onClickCell) {
                            _this.opts.onClickCell.call(pNode, _this.colOptArray[col].field, data);
                        }
                    }
                }, 300);
            },
            dblclick: function (e) {
                if (_this.splitedLeftTd || _this.dragging) {
                    return false;
                }
                clearTimeout(_this.clickTimer);
                let pNode = _getTd(e.target);
                let row = parseInt($B.DomUtils.attribute(pNode, "row"));
                let data = _this.formatDataArr[row];
                if (_this.opts.onDbClickRow) {
                    _this.opts.onDbClickRow.call(pNode, data);
                }
            }
        });
        if (this.opts.pgposition === "top" || this.opts.pgposition === "none" || this.opts.isTree) {
            $B.DomUtils.bind(_this.$hsrollEl, {
                mouseenter: function () {
                    $B.DomUtils.css(_this.$hsrollEl, { "overflow-x": "auto" });
                },
                mouseleave: function () {
                    $B.DomUtils.css(_this.$hsrollEl, { "overflow-x": "hidden" });
                }
            });
        } else {
            $B.DomUtils.css(_this.$hsrollEl, { "overflow-x": "auto" });
        }
    }
    checkAllData(ischk) {
        if (this.formatDataArr.length === 0) {
            return;
        }
        var childes = this.$bodyTable.childNodes;
        for (let i = 0; i < childes.length; i++) {
            if ($B.DomUtils.hasClass(childes[i], "_ext_tr")) {
                continue;
            }
            let $i = childes[i].firstChild.firstChild.firstChild;
            if($B.DomUtils.hasClass($i.parentNode,"k_table_chk_disabled")){
                continue;
            }
            if (ischk) {
                this.formatDataArr[i]._checked = true;
                $B.DomUtils.removeClass($i, "fa-check-empty fa-minus-squared");
                $B.DomUtils.addClass($i, "fa-check");
            } else {
                this.formatDataArr[i]._checked = false;
                $B.DomUtils.removeClass($i, "fa-check fa-minus-squared");
                $B.DomUtils.addClass($i, "fa-check-empty");
            }
        }
        if (this.opts.onCheck) {
            setTimeout(() => {
                this.opts.onCheck(this.formatDataArr);
            }, 1);
        }
    }
    _loopParentNodeUI(currentTr) {
        //向前，向后获取同级元素，同时获取父节点
        let deep = parseInt($B.DomUtils.attribute(currentTr, "deep"));
        let allSiblings = [];
        let parentNode;
        let prevEl = currentTr.previousSibling;
        while (prevEl) {
            if ($B.DomUtils.hasClass(prevEl, "_ext_tr")) {
                prevEl = prevEl.previousSibling;
                continue;
            }
            let deep1 = parseInt($B.DomUtils.attribute(prevEl, "deep"));
            if (deep1 < deep) {
                parentNode = prevEl;
                break;
            }
            if (deep1 === deep) { //同级元素
                allSiblings.push(prevEl);
            }
            prevEl = prevEl.previousSibling;
        }
        if (!parentNode) {
            return;
        }
        let nextEl = currentTr.nextSibling;
        while (nextEl) {
            if ($B.DomUtils.hasClass(nextEl, "_ext_tr")) {
                nextEl = nextEl.previousSibling;
                continue;
            }
            let deep1 = parseInt($B.DomUtils.attribute(nextEl, "deep"));
            if (deep1 < deep) {
                break;
            }
            if (deep1 === deep) { //同级元素
                allSiblings.push(nextEl);
            }
            nextEl = nextEl.nextSibling;
        }
        let all = allSiblings.length + 1;
        let checkedCount = 0;
        let row = parseInt($B.DomUtils.attribute(currentTr.firstChild, "row"));
        if (this.formatDataArr[row]._checked) {
            checkedCount = 1;
        }
        for (let i = 0; i < allSiblings.length; i++) {
            let row = parseInt($B.DomUtils.attribute(allSiblings[i].firstChild, "row"));
            if (this.formatDataArr[row]._checked) {
                checkedCount++;
            }
        }
        let $icon = parentNode.firstChild.firstChild.firstChild;
        row = parseInt($B.DomUtils.attribute(parentNode.firstChild, "row"));
        let parentBean = this.formatDataArr[row];
        parentBean._checked = false;
        if (checkedCount === all) { //全选
            $B.DomUtils.removeClass($icon, "fa-check-empty fa-minus-squared");
            $B.DomUtils.addClass($icon, "fa-check");
            parentBean._checked = true;
        } else if (checkedCount === 0) {//全不选
            $B.DomUtils.removeClass($icon, "fa-check fa-minus-squared");
            $B.DomUtils.addClass($icon, "fa-check-empty");
        } else {//部分选
            $B.DomUtils.removeClass($icon, "fa-check fa-check-empty");
            $B.DomUtils.addClass($icon, "fa-minus-squared");
        }
        this._loopParentNodeUI(parentNode);
    }
    _fireCheck(td) {
        let $i = td.firstChild.firstChild;
        if(!$B.DomUtils.hasClass($i.parentNode,"k_table_chk_disabled")){
            let row = parseInt($B.DomUtils.attribute(td, "row"));
            let bean = this.formatDataArr[row];
            if ($B.DomUtils.hasClass($i, "fa-check-empty")) {
                $B.DomUtils.removeClass($i, "fa-check-empty fa-minus-squared");
                $B.DomUtils.addClass($i, "fa-check");
                bean._checked = true;
            } else {
                $B.DomUtils.removeClass($i, "fa-check fa-minus-squared");
                $B.DomUtils.addClass($i, "fa-check-empty");
                bean._checked = false;
            }
            if (this.opts.isTree) {//如果是树形
                let tr = td.parentNode;
                let deep = parseInt($B.DomUtils.attribute(tr, "deep"));
                if (bean.children) { //如果是父节点,向下复选
                    let childTr = tr.nextSibling;
                    while (childTr) {
                        if ($B.DomUtils.hasClass(childTr, "_ext_tr")) {
                            childTr = childTr.nextSibling;
                            continue;
                        }
                        let childDeep = parseInt($B.DomUtils.attribute(childTr, "deep"));
                        if (childDeep <= deep) {
                            break;
                        }
                        let rowIdx = parseInt($B.DomUtils.attribute(childTr.firstChild, "row"));
                        this.formatDataArr[rowIdx]._checked = bean._checked;
                        //修饰子元素复选
                        let $icon = childTr.firstChild.firstChild.firstChild;
                        if (bean._checked) {
                            $B.DomUtils.removeClass($icon, "fa-check-empty fa-minus-squared");
                            $B.DomUtils.addClass($icon, "fa-check");
                        } else {
                            $B.DomUtils.removeClass($icon, "fa-check fa-minus-squared");
                            $B.DomUtils.addClass($icon, "fa-check-empty");
                        }
                        childTr = childTr.nextSibling;
                    }
                }
                //向上修饰父节点复选情况
                this._loopParentNodeUI(tr);
            }
            setTimeout(() => {
                this.renderChkUI();
                if (this.opts.onCheck) {
                    setTimeout(() => {
                        this.opts.onCheck(bean);
                    }, 1);
                }
            }, 1);
        }

    }
    renderChkUI() {
        let len = this.formatDataArr.length;
        let chkCount = 0;
        for (let i = 0; i < len; i++) {
            if (this.formatDataArr[i]._checked) {
                chkCount++;
            }
        }
        if (chkCount === 0) { //全不选
            $B.DomUtils.removeClass(this.$chkTdBtn.firstChild, "fa-check fa-minus-squared");
            $B.DomUtils.addClass(this.$chkTdBtn.firstChild, "fa-check-empty");
        } else if (chkCount === len) {//全选
            $B.DomUtils.removeClass(this.$chkTdBtn.firstChild, "fa-check-empty fa-minus-squared");
            $B.DomUtils.addClass(this.$chkTdBtn.firstChild, "fa-check");
        } else {//部分选
            $B.DomUtils.removeClass(this.$chkTdBtn.firstChild, "fa-check fa-check-empty");
            $B.DomUtils.addClass(this.$chkTdBtn.firstChild, "fa-minus-squared");
        }
    }
    _closeToolTip(closeIns) {
        if (closeIns && closeIns.close) {
            closeIns.close();
            return;
        }
        if (this.toolTipIns && this.toolTipIns.close) {
            this.toolTipIns.close();
            this.toolTipIns = undefined;
        }
    }
    _bindTdEvents(td) {
        if (!this.tdEvents) {
            var _this = this;
            var maxHeight = this.opts.lineClamp * lineHeight - 8;
            var tipMonseEvents = {
                mouseenter: function (e) {
                    if (_this.hideToolTiptimter) {
                        clearTimeout(_this.hideToolTiptimter.timer);
                        _this.hideToolTiptimter = undefined;
                    }
                    if (_this.hideToolTiptimter1) {
                        clearTimeout(_this.hideToolTiptimter1.timer);
                        _this.toolTipIns = _this.hideToolTiptimter1.tipIns;
                        _this.hideToolTiptimter1 = undefined;
                    }
                },
                mouseleave: function (e) {
                    e.target.instance.close();
                }
            };
            this.tdEvents = {
                mousedown: function (e) {
                    if (_this.splitedLeftTd) {
                        let td = _this.splitedLeftTd;
                        let col = td._col;
                        let colspan = $B.DomUtils.attribute(td, "colspan");
                        if (colspan) {
                            col = col + parseInt(colspan) - 1;
                        }
                        _this.dragingLeftcol = col;
                        _this.dragingRightcol = _this.splitedRightTd._col;
                        let left = 0;
                        for (let i = 0; i < _this.colWidthArray.length; i++) {
                            left = _this.colWidthArray[i] + left + 1;
                            if (i === col) {
                                break;
                            }
                        }
                        if (!_this.$splitLine) {
                            let splitLine = $B.DomUtils.createEl("<div style='cursor:w-resize;position:absolute;width:1px;height:100%;top:0;left:" + left + "px;margin:0;padding:0px;background:#0DF000'></div>");
                            $B.DomUtils.append(_this.$hsrollEl, splitLine);
                            _this.$splitLine = splitLine;
                            $B.draggable(splitLine, {
                                nameSpace: 'tablesplit',
                                cursor: 'w-resize',
                                axis: 'h', // v or h  水平还是垂直方向拖动 ，默认全向
                                onDragReady: function (args) {
                                    return true;
                                },
                                onStartDrag: function (args) {
                                    _this.dragging = true;
                                },
                                onDrag: function (args) {
                                },
                                onStopDrag: function (args) {
                                    splitLine.style.display = "none";
                                    setTimeout(() => {
                                        _this.dragging = false;
                                    }, 360);
                                    let leftOfs = args.state._data.leftOffset;
                                    _this.onDragColWidth(leftOfs, _this.dragingLeftcol, _this.dragingRightcol);
                                    return false;
                                },
                                onMouseUp: function (args) {
                                    splitLine.style.display = "none";
                                    setTimeout(() => {
                                        _this.dragging = false;
                                    }, 360);
                                }
                            });
                        } else {
                            _this.$splitLine.style.left = left + "px";
                            _this.$splitLine.style.display = "block";
                        }
                        $B.DomUtils.trigger(_this.$splitLine, "tablesplit.mousedown", e);
                        return false;
                    }
                },
                mouseenter: function (e) {
                    let td = e.target;
                    while (td) {
                        if (td.tagName === "TD") {
                            break;
                        }
                        td = td.parentNode;
                    }
                    let offset = $B.DomUtils.offset(td);
                    let colIdx = $B.Dom.attr(td,"col"); 
                    let headTd = _this.colTdMap[colIdx];
                    let width = _this.colWidthArray[td._col];
                    let start = offset.left;
                    let end = offset.left + width;
                    td._compareArgs = { s1: start - 3, s2: start + 3, e1: end - 3, e2: end + 3 };
                    if (td._isHeader) {
                        return;
                    }
                    if (_this.hideToolTiptimter) {
                        clearTimeout(_this.hideToolTiptimter.timer);
                        _this.hideToolTiptimter = undefined;
                    }
                    if (_this.toolTipIns) {
                        let tipIns = _this.toolTipIns;
                        _this.toolTipIns = undefined;
                        let timer = setTimeout(() => {
                            _this._closeToolTip(tipIns);
                        }, 600);
                        _this.hideToolTiptimter1 = {
                            timer: timer,
                            td: e.target,
                            tipIns: tipIns
                        };
                    }
                    let wrap = e.target.firstChild;
                    let tipAttr = $B.Dom.attr(headTd,"tip");
                    let isTip = tipAttr !== undefined;
                    if(!isTip){
                        let h = $B.DomUtils.innerHeight(wrap);
                        isTip = h > maxHeight;
                    }                    
                    if (isTip) {  
                        let tipColor,tipText = wrap.firstChild.innerText;
                        if(_this.opts.formatTipFn){                            
                            let rowIdx = parseInt( $B.Dom.attr(td,"row"));
                            let colName = $B.Dom.attr(headTd,"field"); 
                            let rowData = _this.formatDataArr[rowIdx];
                            let ret = _this.opts.formatTipFn(colName,rowData,colIdx,rowIdx);
                            if(ret){
                                if(typeof ret === "string"){
                                    if(ret.indexOf("#") === 0){
                                        tipColor = ret;
                                    }else{
                                        tipText = ret;
                                    }
                                }else{
                                    tipColor = ret.color;
                                    tipText = ret.text;
                                }
                            }
                        }                                     
                        _this.toolTipIns = $B.toolTip(wrap, tipText,undefined,tipColor);
                        $B.DomUtils.bind(_this.toolTipIns.elObj, tipMonseEvents);
                        if (_this.hideToolTiptimter1) {
                            _this.hideToolTiptimter1.tipIns = _this.toolTipIns;
                        }
                    }
                    return false;
                },
                mouseleave: function (e) {
                    e.target._compareArgs = undefined;
                    if (e.target._isHeader) {
                        return;
                    }
                    let timer = setTimeout(() => {
                        _this._closeToolTip();
                    }, 600);
                    _this.hideToolTiptimter = {
                        timer: timer,
                        td: e.target
                    };
                    _this._changeTdMouse(e.target, "default");
                    return false;
                },
                mousemove: function (e) {
                    let td = e.target;
                    while (td) {
                        if (td.tagName === "TD") {
                            break;
                        }
                        td = td.parentNode;
                    }
                    var pageX = e.pageX;
                    var args = td._compareArgs;
                    let leftTd, rightTd;
                    if (args.s1 <= pageX && pageX <= args.s2) {
                        leftTd = td.previousSibling;
                        rightTd = td;
                    } else if (args.e1 <= pageX && pageX <= args.e2) {
                        rightTd = td.nextSibling;
                        leftTd = td;
                    }
                    _this.splitedLeftTd = undefined;
                    _this.splitedRightTd = undefined;
                    if (leftTd && rightTd && !leftTd._ischk) {
                        _this._changeTdMouse(td, "w-resize");
                        _this._onSplited = true;
                        _this.splitedLeftTd = leftTd;
                        _this.splitedRightTd = rightTd;
                    } else {
                        _this._changeTdMouse(td, "default");
                    }
                }
            }
        }
        $B.DomUtils.bind(td, this.tdEvents);
    }
    onDragColWidth(shift, leftTd, rightTd) {
        let leftOpt = this.colOptArray[leftTd];
        let rightOpt = this.colOptArray[rightTd];
        let leftWidth = this.colWidthArray[leftTd];
        let rightWidth = this.colWidthArray[rightTd];
        let newLeftWidth, newRightWidth;
        if (shift < 0) { //向左边调整
            newLeftWidth = leftWidth + shift;
            if (newLeftWidth <= leftOpt.minWidth) { //限制最小宽度
                let diff = leftOpt.minWidth - newLeftWidth;
                newLeftWidth = leftOpt.minWidth;
                shift = shift + diff;
            }
            let wrapWidth = $B.DomUtils.width(this.$hsrollEl);
            let bodyWidth = $B.DomUtils.width(this.$bodyWrap.parentNode.parentNode);
            let scrollWidth = bodyWidth - wrapWidth;
            if (scrollWidth < Math.abs(shift)) {
                newRightWidth = rightWidth - shift;
            } else {
                newRightWidth = rightWidth;
            }
        } else {//向右边调整
            newRightWidth = rightWidth - shift;
            if (newRightWidth < rightOpt.minWidth) {
                newRightWidth = rightOpt.minWidth;
            }
            newLeftWidth = leftWidth + shift;
        }
        this.colWidthArray[leftTd] = newLeftWidth;
        this.colWidthArray[rightTd] = newRightWidth;
        this._updateHeaderWidth(this.colWidthArray);
        this.asyncWidth();
    }
    _changeTdMouse(el, cursor) {
        el.style.cursor = cursor;
        if (el.children) {
            for (let i = 0; i < el.children; i++) {
                this._changeTdMouse(el.children[i], cursor);
            }
        }
    }
    _updateSrollIcon() {
        if (this.$scrolyIcon) {
            let scolLeft = $B.DomUtils.scrollLeft(this.$hsrollEl);
            let scrollWidth = this.$hsrollEl.scrollWidth;
            let width = this.$hsrollEl.clientWidth;
            let right = scrollWidth - width;
            if (right < 0) {
                right = 0;
            } else {
                right = right - scolLeft;
            }
            this.$scrolyIcon.style.right = right + "px";
        }
    }
    createPagination() {
        if (this.opts.pgposition !== "none") {
            _createPagination(this);
        }
    }
    reload(params) {
        this.lastQueryParams = undefined;
        this._load(params);
    }
    refresh(){
        this._load(this.lastQueryParams);
    }
    updateTitle(title){
        let $span = $B.DomUtils.children(this.$H6,".k_table_h_txt")[0];
        $span.innerHTML = title;
    }
    _load(params, callBack) {
        var url = this.opts.url;
        let method = (url.indexOf(".data") > 0 || url.indexOf(".json") > 0) ? "GET" : "POST";
        var _this = this;
        if (this.opts.showLoading && !this.loading && !callBack) {
            this.loading = $B.DomUtils.createEl("<div class='k_box_size' style='position:absolute;top:0;left:0;overflow:hidden;height:100%;width:100%;'><div class='k_model_mask k_box_size' style='position:absolute;width:100%;height:100%;top:0;left:0;'></div></div>");
            let loadel = $B.getLoadingEl(undefined, "#F5F2FF"); 
            //当前是空表格插入一个空行占位
            if (this.$bodyTable.childNodes.length === 0) {
                this.extTr = _appendEmptyTr(this, "");
            }
            $B.DomUtils.append(this.loading, loadel);
            $B.DomUtils.append(this.$bodyWrap, this.loading);
        }
        var datas = { page: this.page, pageSize: this.opts.pageSize };
        if (params) {
            // datas.page = 1; //有参数请求恢复到第一页
            // this.page = 1;
            datas = $B.extendObjectFn(datas, params);
        }
        if (this.opts.setParams) {
            let p = this.opts.setParams(datas);
            if (p) {
                datas = $B.extendObjectFn(datas, p);
            }
        }
        if (this.opts.sortField) {
            let keys = Object.keys(this.opts.sortField);
            for (let i = 0; i < keys.length; i++) {
                let skey = this.opts.sortFieldPrex + keys[i];
                if (!datas[skey]) {
                    datas[skey] = this.opts.sortField[keys[i]];
                }
            }
        }
        let extTrKeys = Object.keys(this.exttrMap);
        for (let i = 0; i < extTrKeys.length; i++) {
            $B.DomUtils.offEvents(this.exttrMap[extTrKeys[i]]);
        }
        this.exttrMap = {};
        this.lastQueryParams = datas;       
        let reqOpt = {
            dataType: 'json',
            url: url,
            data: datas,
            type: method,
            onErrorEval: true,
            onReturn: function () {
                if (callBack) {
                    callBack(0, undefined);
                    return;
                }
                if(_this.loading){
                    let $l = _this.loading;
                    _this.loading = undefined;
                    try {
                        $B.removeLoading($l, () => {
                        });
                        if (_this.extTr) {
                            _this.extTr.parentNode.removeChild(_this.extTr);
                            _this.extTr = undefined;
                        }
                    } catch (ex) {
                        console.log(ex);
                    }
                }                
            },
            ok: function (message, data) {
                if(_this.$chkTdBtn){
                    $B.DomUtils.removeClass(_this.$chkTdBtn.firstChild, "fa-check fa-minus-squared");
                    $B.DomUtils.addClass(_this.$chkTdBtn.firstChild, "fa-check-empty");
                }                
                if (!data.resultList && !_this.opts.isTree) {
                    $B.error("the return data format must be：{resultList:[{}],totalSize:xxxx}");
                    return;
                }
                if (callBack) {
                    callBack(1, data);
                    _this._triggerExentdTrs();
                    return;
                }
                _this.opts.data = data;
                if (_this.opts.isTree) { //树形                   
                    _cretteTreeTableBody(_this);
                } else {
                    _cretteTableBody(_this);
                }
                _this._triggerExentdTrs();
            },
            final: function (res, status, xhr) {
                if (_this.opts.onLoaded) {
                    setTimeout(() => {
                        _this.opts.onLoaded(res, status);
                    }, 1);
                }
            }
        };
        if(!this.showLoading){
            reqOpt.error= function (xhr, status, errorThrown){
                console.log("error:",xhr,status);
            };
            reqOpt.fail = function (msg, res){
                console.log("fail:",msg, res);
            };
        }
        $B.request(reqOpt);
    }
    fit2height() {
        if (this.opts.fit2height) {
            let maxHeight = $B.DomUtils.innerHeight(this.elObj.parentNode);            
            let childs = this.elObj.childNodes;
            let h = 2, tmp;
            for (let i = 0; i < childs.length; i++) {
                tmp = $B.DomUtils.outerHeight(childs[i]);
                h = h + tmp;
            }
            let aviHeight = maxHeight - h;
            let $wrap = this.$bodyWrap.parentNode.parentNode;          
            $B.DomUtils.height($wrap, aviHeight);
        }
    }
    /***
     * 根据colWidthArray设置表格各列宽度
     * ***/
    asyncWidth() {
        if (this.formatDataArr.length === 0) {
            if (this.$emptyTr) {
                let w = $B.DomUtils.width(this.$bodyTable.parentNode);
                $B.DomUtils.width(this.$emptyTr.firstChild.firstChild, { width: w });
            }
            return;
        }
        var tr = this.$bodyTable.firstChild;
        while(tr){
            var childNodes = tr.childNodes;
            let isHline = this.opts.splitColLine === "k_table_td_none_line" || this.opts.splitColLine === "k_table_td_h_line";
            for (let i = 0; i < childNodes.length; i++) {
                let tdWidth = this.colWidthArray[i];
                if (isHline) {
                    tdWidth++;
                }
                $B.DomUtils.width(childNodes[i].firstChild, tdWidth);
            }
            tr = tr.nextSibling;
        }
    }
    getRowCount(){   
        return this.$bodyTable.children.length;
    }
    getCheckedData(forId) {
        var datas = [];
        for (let i = 0; i < this.formatDataArr.length; i++) {
            if (this.formatDataArr[i]._checked) {
                if (forId) {
                    if (this.opts.isTree) {
                        if (typeof this.formatDataArr[i].id !== "undefined") {
                            datas.push(this.formatDataArr[i].id);
                        } else {
                            datas.push(this.formatDataArr[i].data[this.opts.idField]);
                        }
                    } else {
                        datas.push(this.formatDataArr[i][this.opts.idField]);
                    }
                } else {
                    datas.push(this.formatDataArr[i]);
                }
            }
        }
        return datas;
    }
    openInner(tr){
        this._initExtTrEvent();
        this.extentTrEvent({target:tr});
    }
    /***
     * 扩展行展开功能
     * **/
    extendTr(tr) {
        let td = tr.firstChild;
        if (this.opts.checkBox) {
            td = td.nextSibling;
        }
        if (!$B.DomUtils.attribute(td, "exttr")) {
            $B.DomUtils.attribute(td, { "exttr": 1 });
            let wrap = td.firstChild.firstChild;
            let iconNode = $B.DomUtils.createEl("<span style='padding-left:3px;cursor:pointer;' ><i class='fa fa-right-open-1 ext_tr_closed'></i></span>");
            if (this.opts.isTree) {
                $B.DomUtils.css(iconNode, { "padding-right": "8px" });
                $B.DomUtils.after(wrap.lastElementChild, iconNode);
            } else {
                let html = "<span style='padding-left:6px;'>" + wrap.innerHTML + "</span>";
                let newNode = $B.DomUtils.createEl(html);
                wrap.innerHTML = "";
                $B.DomUtils.append(wrap, iconNode);
                $B.DomUtils.append(wrap, newNode);
            }
            this._initExtTrEvent();
            $B.DomUtils.click(iconNode, this.extentTrEvent);
            if (this.opts.openExtendTr) {//如果是需要打开展开行的
                if (!this.triggerExtendTrs) {
                    this.triggerExtendTrs = [];
                }
                this.triggerExtendTrs.push(iconNode);
            }
        }
    }
    _initExtTrEvent(){
        var _this = this;
        if (!this.extentTrEvent) {
            this.extentTrEvent = function (e) {
                let el = e.target;
                let td,data,rowNum,extId,$extTr,  isShow = true;;
                if(el.tagName === "TR"){
                    td = el.firstChild;
                    rowNum = td._row;
                    data = _this.formatDataArr[rowNum];
                    extId = "ext_tr" + rowNum;                   
                    let trId = "";
                    let nextTr = el.nextSibling;
                    if(nextTr){
                        trId = nextTr.id;
                    }                    
                    if(extId === trId){
                        $extTr = nextTr;
                        isShow = false;
                        $B.DomUtils.remove($extTr);
                    }else{
                        $extTr = $B.DomUtils.createEl("<tr class='_ext_tr' id='" + extId + "'><td style='min-height:32px;padding:3px 4px;' colspan='" + _this.colOptArray.length + "'></td></tr>");
                        $B.DomUtils.after(el, $extTr);
                    }
                }else{
                    if (el.tagName === "SPAN") {
                        el = el.firstChild;
                    }
                    td = el.parentNode;
                    while (td) {
                        if (td.tagName === "TD") {
                            break;
                        }
                        td = td.parentNode;
                    }
                    rowNum = td._row;
                    data = _this.formatDataArr[rowNum];
                    extId = "ext_tr" + rowNum;
                    if (!_this.exttrMap[extId]) {
                        _this.exttrMap[extId] = $B.DomUtils.createEl("<tr class='_ext_tr' id='" + extId + "'><td style='min-height:32px;padding:3px 4px;' colspan='" + _this.colOptArray.length + "'></td></tr>");
                    }
                    $extTr =  _this.exttrMap[extId];                   
                    if ($B.DomUtils.hasClass(el, "ext_tr_closed")) { //执行展开
                        $B.DomUtils.removeClass(el, "ext_tr_closed");
                        $B.animate(el, { "rotateZ": "90deg" }, { duration: 200 });
                        $B.DomUtils.after(td.parentNode, _this.exttrMap[extId]);
                    } else {//执行收起
                        $B.DomUtils.addClass(el, "ext_tr_closed");
                        $B.animate(el, { "rotateZ": "0deg" }, { duration: 200 });
                        $B.DomUtils.detach(_this.exttrMap[extId]);
                        isShow = false;
                    }
                }
                if (_this.opts.onTrExtended) {
                    setTimeout(() => {
                        _this.opts.onTrExtended(data, $extTr, isShow);
                    }, 1);
                }
                return false;
            };
        }
    }
    /***
     * args = {colindx:width} 4008205555  
     * ***/
    autoHeaderWidth(args) {
        let newWidth = [];
        let colTdArray = $B.DomUtils.children(this.$hideTr);
        let td, tdWidth;
        let colCount = colTdArray.length;
        for (let i = 0; i < colCount; i++) {
            td = colTdArray[i];
            tdWidth = $B.DomUtils.width(td.firstChild);
            if (args && args[i]) {
                newWidth.push(args[i]);
            } else {
                newWidth.push(tdWidth);
            }
        }
        //总宽度小于外层宽度
        let wrapWidth = $B.DomUtils.width(this.$headWrap);
        let diff = wrapWidth - $B.DomUtils.width(this.$headTable) - 1;
        if (diff > 0) {
            let avg = Math.floor(diff / this.autoCols.length);
            if (avg > 1) { //可均分到每列最少1px
                let leftVal = diff % this.autoCols.length;
                let j = 0;
                while (j < colCount) {
                    if (this.autoCols.includes(j)) {
                        newWidth[j] = newWidth[j] + avg;
                    }
                    j++;
                }
                newWidth[colCount - 1] = newWidth[colCount - 1] + leftVal;
            } else { //只将余量放在最后一列即可
                newWidth[colCount - 1] = newWidth[colCount - 1] + diff;
            }
        } else {

        }
        this._updateHeaderWidth(newWidth);
    }
    _updateHeaderWidth(newWidth) {
        let clonetr = this.$hideTr.cloneNode(true);
        var childNodes = clonetr.childNodes;
        for (let i = 0; i < childNodes.length; i++) {
            $B.DomUtils.width(childNodes[i].firstChild, newWidth[i]);
        }
        $B.DomUtils.before(this.$hideTr, clonetr);
        $B.DomUtils.remove(this.$hideTr);
        this.$hideTr = clonetr;
        this.colWidthArray = newWidth;
        let bodyWidth = $B.DomUtils.outerWidth(this.$headTable);
        let $wrap = this.$bodyWrap.parentNode.parentNode;
        $B.DomUtils.width($wrap, bodyWidth);
        //console.log("bodyWidth " + bodyWidth);
    }
    destroyTools() {
        if (this.toolbarIns) {
            this.toolbarIns.destroy();
            this.toolbarIns = undefined;
        }
        if (this.topPgIns) {
            this.topPgIns.destroy();
            this.topPgIns = undefined;
        }
    }
    destroyBottomTools() {
        if (this.bottomPgIns) {
            this.bottomPgIns.destroy();
            this.bottomPgIns = undefined;
        }
    }
    destroyRowTools() {
        for (let i = 0; i < this.rowTools.length; i++) {
            this.rowTools[i].destroy();
        }
        this.rowTools = [];
    }
    destroy(isForce) {
        this.destroyRowTools();
        this.destroyTools();
        this.destroyBottomTools();
        $B.DomUtils.offEvents(window, this.resizeEvent);
        super.destroy();
    }
}
$B["Table"] = Table;